﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;//
using Xbim.Ifc;
using Xbim.ModelGeometry.Scene;//
using Xbim.Common.Step21;
using Xbim.Common;
using Xbim.Ifc4.Kernel;
using Xbim.Ifc4.SharedBldgElements;
using Xbim.Ifc4.PropertyResource;
using Xbim.Ifc4.MeasureResource;
using Xbim.Ifc4.Interfaces;
using Newtonsoft.Json;
using Xbim.Ifc4.ElectricalDomain;
using Xbim.Ifc4.ProfileResource;
using Xbim.Ifc4.GeometryResource;
using Xbim.Ifc4.GeometricModelResource;
using Xbim.Ifc4.RepresentationResource;
using Xbim.Ifc4.GeometricConstraintResource;
using Xbim.Ifc4.MaterialResource;
using Xbim.Ifc4.ProductExtension;
using Xbim.Ifc4.PresentationOrganizationResource;
using Xbim.Ifc4.QuantityResource;
using Xbim.Ifc4.ActorResource;
using Xbim.Ifc4.DateTimeResource;
using Xbim.Ifc4.ExternalReferenceResource;
     
namespace xBimServer.Controllers
{
    public class BimIfc4Controller : Controller
    {



        public ActionResult CreateWall(string wFileName)
        {
            string fileName = Server.MapPath(@"\res\ifc\CreateWall_Demo.ifc");
            if (!string.IsNullOrEmpty(wFileName))
            {
                fileName = Server.MapPath(wFileName);
            }

            var lsInfo = new List<NodeInfo>();
            #region  
            using (var model = CreateandInitModel("HelloWall"))
            {
                if (model != null)
                {
                    IfcBuilding building = CreateBuilding(model, "Default Building 默认建筑");
                    IfcBuildingStorey storey = CreateStorey(building);
                    IfcWallStandardCase wall = CreateWall(model, 4000, 30, 2400);

                    IfcAudioVisualAppliance audioVedio1 = CreateAudioVideo(model, "东门摄像头", 30, 30, 30, 100, 100, 100);
                    IfcAudioVisualAppliance audioVedio2 = CreateAudioVideo(model, "南门摄像头", 60, 60, 60, 100, 500, 200);
                    IfcAudioVisualAppliance audioVedio3 = CreateAudioVideo(model, "西门摄像头", 90, 90, 90, 500, 100, 300);
                    IfcAudioVisualAppliance audioVedio4 = CreateAudioVideo(model, "北门摄像头", 120, 120, 120, 500, 500, 400);
                    IfcAudioVisualAppliance audioVedio5 = CreateAudioVideo(model, "中门摄像头", 150, 150, 150, 500, 500, 1500);
                    if (wall != null)
                    {
                        AddPropertiesToWall(model, wall);
                    }
                    using (var txn = model.BeginTransaction("Add Wall 添加墙"))
                    {
                        building.AddToSpatialDecomposition(storey);
                        storey.AddElement(wall);
                        txn.Commit();
                    }

                    if (wall != null)
                    {
                        try
                        {
                            Console.WriteLine("Standard Wall successfully created....");

                            model.SaveAs(fileName);// , StorageType.Ifc); // 保存到文件中

                            Console.WriteLine("HelloWallIfc4.ifc has been successfully written");
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("Failed to save HelloWall.ifc");
                            Console.WriteLine(e.Message);
                        }
                    }
                }
                else
                {
                    Console.WriteLine("Failed to initialise the model");
                }
            }
            #endregion
            return Content(JsonConvert.SerializeObject(lsInfo), "application/json");
            //return Json(lsInfo, JsonRequestBehavior.AllowGet);
        }
        // 

        #region
      
        /// <summary>
        ///  设置任何模型必须提供的基本参数、单位、所有权等
        /// </summary>
        /// <param name="projectName">项目名称</param>
        /// <returns></returns>
        private static IfcStore CreateandInitModel(string projectName)
        {
            // 首先，我们需要为新模型中的数据所有权设置一些凭证
            var credentials = new XbimEditorCredentials
            {
                ApplicationDevelopersName = "xBimTeam",
                ApplicationFullName = "Hello Wall Application",
                ApplicationIdentifier = "HelloWall.exe",
                ApplicationVersion = "1.0",
                EditorsFamilyName = "Team",
                EditorsGivenName = "xBIM",
                EditorsOrganisationName = "xBimTeam"
            };

            // 现在我们可以创建一个ifcstore，它是ifc4格式的，将保存在内存中而不是数据库中。
            // 如果模型的容量大于50MB，或者需要健壮的事务，那么数据库在性能方面通常更好。

            var model = IfcStore.Create(credentials, IfcSchemaVersion.Ifc4, XbimStoreType.InMemoryModel);//, XbimSchemaVersion.Ifc4, XbimStoreType.InMemoryModel);

            // 开始事务，因为对模型的所有更改都是ACID
            using (var txn = model.BeginTransaction("Initialise Model 初始化模型"))
            {
                var project = model.Instances.New<IfcProject>(); // 创建一个项目
                project.Initialize(ProjectUnits.SIUnitsUK); // 将单位设置为si（mm和米）
                project.Name = projectName;

                txn.Commit(); // 现在提交更改，否则它们将在using语句的范围结束时回滚。
            }

            return model;
        }

        ///  创建建筑对象
        /// </summary>
        /// <param name="model"></param>
        /// <param name="name">建筑名称</param>
        /// <returns></returns>
        private static IfcBuilding CreateBuilding(IfcStore model, string name)
        {
            using (var txn = model.BeginTransaction("Create Building 创建建筑对象"))
            {
                var building = model.Instances.New<IfcBuilding>();
                building.Name = name;
                building.CompositionType = IfcElementCompositionEnum.ELEMENT; // 组成类型

                var localPlacement = model.Instances.New<IfcLocalPlacement>();
                building.ObjectPlacement = localPlacement;

                var placement = model.Instances.New<IfcAxis2Placement3D>();
                localPlacement.RelativePlacement = placement;
                placement.Location = model.Instances.New<IfcCartesianPoint>(p => p.SetXYZ(0, 0, 0));

                // 获取第一个或者默认的项目
                var project = model.Instances.OfType<IfcProject>().FirstOrDefault();
                if (project != null)
                {
                    project.AddBuilding(building);
                }

                txn.Commit();

                return building;
            }
        }

        private static IfcBuildingStorey CreateStorey(IfcBuilding building)
        {
            var model = building.Model;
            IfcBuildingStorey storey;
            using (var txn = model.BeginTransaction("Storey creation"))
            {
                storey = model.Instances.New<IfcBuildingStorey>(s =>
                {
                    s.Name = "Default storey";
                    s.Elevation = 0.0;
                });
                txn.Commit();
            }
            return storey;
        }



        /// <summary>
        ///  创建一个墙和它的几何图形，许多几何图形表示是可能的，并选择挤压矩形示意图，因为这通常用于标准情况下的墙。
        /// </summary>
        /// <param name="model"></param>
        /// <param name="length">矩形足迹的长度</param>
        /// <param name="width">矩形足迹的宽度（墙的宽度）</param>
        /// <param name="height">挤出墙的高度，挤出是垂直的</param>
        /// <returns></returns>
        static private IfcWallStandardCase CreateWall(IfcStore model, double length, double width, double height)
        {
            using (var txn = model.BeginTransaction("Create Wall 创建墙"))
            {
                var wall = model.Instances.New<IfcWallStandardCase>(); //IfcWallStandardCase：IFC墙标准案例
                wall.Name = "A Standard rectangular wall 标准矩形墙";

                // 将墙表示为矩形轮廓，墙的矩形剖面
                var rectProf = model.Instances.New<IfcRectangleProfileDef>(); //IfcRectangleProfileDef：IFC矩形轮廓定义
                rectProf.ProfileType = IfcProfileTypeEnum.AREA;
                rectProf.XDim = width;
                rectProf.YDim = length;

                var insertPoint = model.Instances.New<IfcCartesianPoint>(); //IfcCartesianPoint：IFc 笛卡尔点
                insertPoint.SetXY(0, 400); //在任意位置插入
                rectProf.Position = model.Instances.New<IfcAxis2Placement2D>();
                rectProf.Position.Location = insertPoint;

                // 模型区域实心
                var body = model.Instances.New<IfcExtrudedAreaSolid>(); //IfcExtrudedAreaSolid：IFC拉伸区域实体
                body.Depth = height;
                body.SweptArea = rectProf;
                body.ExtrudedDirection = model.Instances.New<IfcDirection>();//IfcDirection：IFC方向
                body.ExtrudedDirection.SetXYZ(0, 0, 1);

                // 在模型中插入几何参数
                var origin = model.Instances.New<IfcCartesianPoint>(); //IfcCartesianPoint：IFc 笛卡尔点
                origin.SetXYZ(0, 0, 0);
                body.Position = model.Instances.New<IfcAxis2Placement3D>();
                body.Position.Location = origin;

                // 创建定义形状以保存几何图形
                var shape = model.Instances.New<IfcShapeRepresentation>();//IfcShapeRepresentation：IFC形状表示
                var modelContext = model.Instances.OfType<IfcGeometricRepresentationContext>().FirstOrDefault(); //IfcGeometricRepresentationContext：IFC几何表示上下文
                shape.ContextOfItems = modelContext;
                shape.RepresentationType = "SweptSolid";
                shape.RepresentationIdentifier = "Body";
                shape.Items.Add(body);

                // 创建产品定义并将模型几何图形添加到墙中
                var rep = model.Instances.New<IfcProductDefinitionShape>(); //IfcProductDefinitionShape：IFC产品定义形状
                rep.Representations.Add(shape);
                wall.Representation = rep;

                // 现在将墙放置到模型中
                var lp = model.Instances.New<IfcLocalPlacement>();
                var ax3D = model.Instances.New<IfcAxis2Placement3D>();
                ax3D.Location = origin;
                ax3D.RefDirection = model.Instances.New<IfcDirection>();
                ax3D.RefDirection.SetXYZ(0, 1, 0);
                ax3D.Axis = model.Instances.New<IfcDirection>();
                ax3D.Axis.SetXYZ(0, 0, 1);
                lp.RelativePlacement = ax3D;
                wall.ObjectPlacement = lp;

                // Where Clause: ifcwallstandardard 依赖于 ifcmmateriallayersetusage 的规定。
                var ifcMaterialLayerSetUsage = model.Instances.New<IfcMaterialLayerSetUsage>();
                var ifcMaterialLayerSet = model.Instances.New<IfcMaterialLayerSet>();
                var ifcMaterialLayer = model.Instances.New<IfcMaterialLayer>();
                ifcMaterialLayer.LayerThickness = 10;
                ifcMaterialLayerSet.MaterialLayers.Add(ifcMaterialLayer);
                ifcMaterialLayerSetUsage.ForLayerSet = ifcMaterialLayerSet;
                ifcMaterialLayerSetUsage.LayerSetDirection = IfcLayerSetDirectionEnum.AXIS2;
                ifcMaterialLayerSetUsage.DirectionSense = IfcDirectionSenseEnum.NEGATIVE;
                ifcMaterialLayerSetUsage.OffsetFromReferenceLine = 150;

                // 将材料添加到墙商
                var material = model.Instances.New<IfcMaterial>();
                material.Name = "some material";
                var ifcRelAssociatesMaterial = model.Instances.New<IfcRelAssociatesMaterial>();
                ifcRelAssociatesMaterial.RelatingMaterial = material;
                ifcRelAssociatesMaterial.RelatedObjects.Add(wall);

                ifcRelAssociatesMaterial.RelatingMaterial = ifcMaterialLayerSetUsage;

                // ifcPresentationLayerAssignment 对于 ifcwall 或 ifcwallstandardcase 中的 CAD 演示是必须的 
                var ifcPresentationLayerAssignment = model.Instances.New<IfcPresentationLayerAssignment>();
                ifcPresentationLayerAssignment.Name = "some ifcPresentationLayerAssignment";
                ifcPresentationLayerAssignment.AssignedItems.Add(shape);


                // 如果 IfcPolyline 具有两个点，则对于 IfcWall 是必需的
                var ifcPolyline = model.Instances.New<IfcPolyline>();
                var startPoint = model.Instances.New<IfcCartesianPoint>();
                startPoint.SetXY(0, 0);
                var endPoint = model.Instances.New<IfcCartesianPoint>();
                endPoint.SetXY(4000, 0);
                ifcPolyline.Points.Add(startPoint);
                ifcPolyline.Points.Add(endPoint);

                var shape2D = model.Instances.New<IfcShapeRepresentation>();
                shape2D.ContextOfItems = modelContext;
                shape2D.RepresentationIdentifier = "Axis";
                shape2D.RepresentationType = "Curve2D";
                shape2D.Items.Add(ifcPolyline);
                rep.Representations.Add(shape2D);
                txn.Commit();

                return wall;
            }
        }

        static private IfcAudioVisualAppliance CreateAudioVideo(IfcStore model,string name, double length, double width, double height,double x,double y,double z)
        {
            using (var txn = model.BeginTransaction("Create Wall 创建墙"))
            {
                var wall = model.Instances.New<IfcAudioVisualAppliance>(); //IfcWallStandardCase：IFC墙标准案例
                wall.Name = name;

                #region  绘制一个实心块 body
                // 将墙表示为矩形轮廓，墙的矩形剖面
                var rectProf = model.Instances.New<IfcRectangleProfileDef>(); //IfcRectangleProfileDef：IFC矩形轮廓定义
                rectProf.ProfileType = IfcProfileTypeEnum.AREA;
                rectProf.XDim = width;
                rectProf.YDim = length;

                var insertPoint = model.Instances.New<IfcCartesianPoint>(); //IfcCartesianPoint：IFc 笛卡尔点
                insertPoint.SetXYZ(x,y,z); //在任意位置插入
                rectProf.Position = model.Instances.New<IfcAxis2Placement2D>();
                rectProf.Position.Location = insertPoint;

                // 模型区域实心
                var body = model.Instances.New<IfcExtrudedAreaSolid>(); //IfcExtrudedAreaSolid：IFC拉伸区域实体
                body.Depth = height;
                body.SweptArea = rectProf;
                body.ExtrudedDirection = model.Instances.New<IfcDirection>();//IfcDirection：IFC方向
                body.ExtrudedDirection.SetXYZ(0, 0, 1);

                // 在模型中插入几何参数
                var origin = model.Instances.New<IfcCartesianPoint>(); //IfcCartesianPoint：IFc 笛卡尔点
                origin.SetXYZ(0, 0, 0);
                body.Position = model.Instances.New<IfcAxis2Placement3D>();
                body.Position.Location = origin;

                #endregion



                // 创建'定义形状'以保存几何图形
                var modelContext = model.Instances.OfType<IfcGeometricRepresentationContext>().FirstOrDefault(); //IfcGeometricRepresentationContext：IFC几何表示上下文
                var shape = model.Instances.New<IfcShapeRepresentation>();//IfcShapeRepresentation：IFC形状表示
                shape.ContextOfItems = modelContext;
                shape.RepresentationType = "SweptSolid";
                shape.RepresentationIdentifier = "Body";
                shape.Items.Add(body);
                // 创建产品定义并将模型几何图形添加到墙中
                var rep = model.Instances.New<IfcProductDefinitionShape>(); //IfcProductDefinitionShape：IFC产品定义形状
                rep.Representations.Add(shape);

                wall.Representation = rep;

                // 现在将墙放置到模型中（设置 其在整个 模型中的位置）
                var ax3D = model.Instances.New<IfcAxis2Placement3D>();
                ax3D.Location = origin;
                ax3D.RefDirection = model.Instances.New<IfcDirection>();
                ax3D.RefDirection.SetXYZ(0, 1, 0);
                ax3D.Axis = model.Instances.New<IfcDirection>();
                ax3D.Axis.SetXYZ(0, 0, 1);

                var lp = model.Instances.New<IfcLocalPlacement>();
                lp.RelativePlacement = ax3D;

                wall.ObjectPlacement = lp;

                // Where Clause: ifcwallstandardard 依赖于 ifcmmateriallayersetusage 的规定。
                //var ifcMaterialLayerSetUsage = model.Instances.New<IfcMaterialLayerSetUsage>();
                //var ifcMaterialLayerSet = model.Instances.New<IfcMaterialLayerSet>();
                //var ifcMaterialLayer = model.Instances.New<IfcMaterialLayer>();
                //ifcMaterialLayer.LayerThickness = 10;
                //ifcMaterialLayerSet.MaterialLayers.Add(ifcMaterialLayer);
                //ifcMaterialLayerSetUsage.ForLayerSet = ifcMaterialLayerSet;
                //ifcMaterialLayerSetUsage.LayerSetDirection = IfcLayerSetDirectionEnum.AXIS2;
                //ifcMaterialLayerSetUsage.DirectionSense = IfcDirectionSenseEnum.NEGATIVE;
                //ifcMaterialLayerSetUsage.OffsetFromReferenceLine = 150;

                // 将材料添加到墙商
                //var material = model.Instances.New<IfcMaterial>();
                //material.Name = "some material";
                //var ifcRelAssociatesMaterial = model.Instances.New<IfcRelAssociatesMaterial>();
                //ifcRelAssociatesMaterial.RelatingMaterial = material;
                //ifcRelAssociatesMaterial.RelatedObjects.Add(wall);

                //ifcRelAssociatesMaterial.RelatingMaterial = ifcMaterialLayerSetUsage;

                // ifcPresentationLayerAssignment 对于 ifcwall 或 ifcwallstandardcase 中的 CAD 演示是必须的 
                var ifcPresentationLayerAssignment = model.Instances.New<IfcPresentationLayerAssignment>();
                ifcPresentationLayerAssignment.Name = "some ifcPresentationLayerAssignment";
                ifcPresentationLayerAssignment.AssignedItems.Add(shape);


                // 如果 IfcPolyline 具有两个点，则对于 IfcWall 是必需的
                var startPoint = model.Instances.New<IfcCartesianPoint>();
                startPoint.SetXY(0, 0);
                var endPoint = model.Instances.New<IfcCartesianPoint>();

                var ifcPolyline = model.Instances.New<IfcPolyline>();
                endPoint.SetXY(4000, 0);
                ifcPolyline.Points.Add(startPoint);
                ifcPolyline.Points.Add(endPoint);

                var shape2D = model.Instances.New<IfcShapeRepresentation>();
                shape2D.ContextOfItems = modelContext;
                shape2D.RepresentationIdentifier = "Axis";
                shape2D.RepresentationType = "Curve2D";
                shape2D.Items.Add(ifcPolyline);

                rep.Representations.Add(shape2D);

                #region 添加属性
                var ifcPropertySingleValue = model.Instances.New<IfcPropertySingleValue>(psv =>
                {
                    psv.Name = "AudioVideo:Time";
                    psv.Description = ""+name;
                    psv.NominalValue = new IfcTimeMeasure(150.0);
                    psv.Unit = model.Instances.New<IfcSIUnit>(siu =>
                    {
                        siu.UnitType = IfcUnitEnum.TIMEUNIT;
                        siu.Name = IfcSIUnitName.SECOND;
                    });
                });
                var ifcPropertySet = model.Instances.New<IfcPropertySet>(ps =>
                {
                    ps.Name = "Test:IfcPropertySet";
                    ps.Description = "Property Set";
                    ps.HasProperties.Add(ifcPropertySingleValue);
                });

                // 需要建立关系
                model.Instances.New<IfcRelDefinesByProperties>(rdbp =>
                {
                    rdbp.Name = "Property Association";
                    rdbp.Description = "IfcPropertySet associated to wall";
                    rdbp.RelatedObjects.Add(wall);
                    rdbp.RelatingPropertyDefinition = ifcPropertySet;
                });

                #endregion

                txn.Commit();

                return wall;
            }
        }
        /// <summary>
        ///  向墙添加一些属性,
        /// </summary>
        /// <param name="model">XbimModel</param>
        /// <param name="wall"></param>
        static private void AddPropertiesToWall(IfcStore model, IfcWallStandardCase wall)
        {
            using (var txn = model.BeginTransaction("Create Wall"))
            {
                CreateElementQuantity(model, wall);
                CreateSimpleProperty(model, wall);
                txn.Commit();
            }
        }

        private static void CreateSimpleProperty(IfcStore model, IfcWallStandardCase wall)
        {
            var ifcPropertySingleValue = model.Instances.New<IfcPropertySingleValue>(psv =>
            {
                psv.Name = "IfcPropertySingleValue:Time";
                psv.Description = "";
                psv.NominalValue = new IfcTimeMeasure(150.0);
                psv.Unit = model.Instances.New<IfcSIUnit>(siu =>
                {
                    siu.UnitType = IfcUnitEnum.TIMEUNIT;
                    siu.Name = IfcSIUnitName.SECOND;
                });
            });
            var ifcPropertyEnumeratedValue = model.Instances.New<IfcPropertyEnumeratedValue>(pev =>
            {
                pev.Name = "IfcPropertyEnumeratedValue:Music";
                pev.EnumerationReference = model.Instances.New<IfcPropertyEnumeration>(pe =>
                {
                    pe.Name = "Notes";
                    pe.EnumerationValues.Add(new IfcLabel("Do"));
                    pe.EnumerationValues.Add(new IfcLabel("Re"));
                    pe.EnumerationValues.Add(new IfcLabel("Mi"));
                    pe.EnumerationValues.Add(new IfcLabel("Fa"));
                    pe.EnumerationValues.Add(new IfcLabel("So"));
                    pe.EnumerationValues.Add(new IfcLabel("La"));
                    pe.EnumerationValues.Add(new IfcLabel("Ti"));
                });
                pev.EnumerationValues.Add(new IfcLabel("Do"));
                pev.EnumerationValues.Add(new IfcLabel("Re"));
                pev.EnumerationValues.Add(new IfcLabel("Mi"));

            });
            var ifcPropertyBoundedValue = model.Instances.New<IfcPropertyBoundedValue>(pbv =>
            {
                pbv.Name = "IfcPropertyBoundedValue:Mass";
                pbv.Description = "";
                pbv.UpperBoundValue = new IfcMassMeasure(5000.0);
                pbv.LowerBoundValue = new IfcMassMeasure(1000.0);
                pbv.Unit = model.Instances.New<IfcSIUnit>(siu =>
                {
                    siu.UnitType = IfcUnitEnum.MASSUNIT;
                    siu.Name = IfcSIUnitName.GRAM;
                    siu.Prefix = IfcSIPrefix.KILO;
                });
            });

            var definingValues = new List<IfcReal> { new IfcReal(100.0), new IfcReal(200.0), new IfcReal(400.0),
                                                         new IfcReal(800.0), new IfcReal(1600.0), new IfcReal(3200.0), };
            var definedValues = new List<IfcReal> { new IfcReal(20.0), new IfcReal(42.0), new IfcReal(46.0),
                                                        new IfcReal(56.0), new IfcReal(60.0), new IfcReal(65.0), };
            var ifcPropertyTableValue = model.Instances.New<IfcPropertyTableValue>(ptv =>
            {
                ptv.Name = "IfcPropertyTableValue:Sound";
                foreach (var item in definingValues)
                {
                    ptv.DefiningValues.Add(item);
                }
                foreach (var item in definedValues)
                {
                    ptv.DefinedValues.Add(item);
                }
                ptv.DefinedUnit = model.Instances.New<IfcContextDependentUnit>(cd =>
                {
                    cd.Dimensions = model.Instances.New<IfcDimensionalExponents>(de =>
                    {
                        de.LengthExponent = 0;
                        de.MassExponent = 0;
                        de.TimeExponent = 0;
                        de.ElectricCurrentExponent = 0;
                        de.ThermodynamicTemperatureExponent = 0;
                        de.AmountOfSubstanceExponent = 0;
                        de.LuminousIntensityExponent = 0;
                    });
                    cd.UnitType = IfcUnitEnum.FREQUENCYUNIT;
                    cd.Name = "dB";
                });


            });

            var listValues = new List<IfcLabel> { new IfcLabel("Red"),
                                                      new IfcLabel("Green"),
                                                      new IfcLabel("Blue"),
                                                      new IfcLabel("Pink"),
                                                      new IfcLabel("White"),
                                                      new IfcLabel("Black"), };
            var ifcPropertyListValue = model.Instances.New<IfcPropertyListValue>(plv =>
            {
                plv.Name = "IfcPropertyListValue:Colours";
                foreach (var item in listValues)
                {
                    plv.ListValues.Add(item);
                }
            });

            var ifcMaterial = model.Instances.New<IfcMaterial>(m =>
            {
                m.Name = "Brick";
            });
            var ifcPrValueMaterial = model.Instances.New<IfcPropertyReferenceValue>(prv =>
            {
                prv.Name = "IfcPropertyReferenceValue:Material";
                prv.PropertyReference = ifcMaterial;
            });


            var ifcMaterialList = model.Instances.New<IfcMaterialList>(ml =>
            {
                ml.Materials.Add(ifcMaterial);
                ml.Materials.Add(model.Instances.New<IfcMaterial>(m => { m.Name = "Cavity"; }));
                ml.Materials.Add(model.Instances.New<IfcMaterial>(m => { m.Name = "Block"; }));
            });


            var ifcMaterialLayer = model.Instances.New<IfcMaterialLayer>(ml =>
            {
                ml.Material = ifcMaterial;
                ml.LayerThickness = 100.0;
            });
            var ifcPrValueMatLayer = model.Instances.New<IfcPropertyReferenceValue>(prv =>
            {
                prv.Name = "IfcPropertyReferenceValue:MaterialLayer";
                prv.PropertyReference = ifcMaterialLayer;
            });

            var ifcDocumentReference = model.Instances.New<IfcDocumentReference>(dr =>
            {
                dr.Name = "Document";
                dr.Location = "c://Documents//TheDoc.Txt";
            });
            var ifcPrValueRef = model.Instances.New<IfcPropertyReferenceValue>(prv =>
            {
                prv.Name = "IfcPropertyReferenceValue:Document";
                prv.PropertyReference = ifcDocumentReference;
            });

            var ifcTimeSeries = model.Instances.New<IfcRegularTimeSeries>(ts =>
            {
                ts.Name = "Regular Time Series";
                ts.Description = "Time series of events";
                ts.StartTime = new IfcDateTime("2015-02-14T12:01:01");
                ts.EndTime = new IfcDateTime("2015-05-15T12:01:01");
                ts.TimeSeriesDataType = IfcTimeSeriesDataTypeEnum.CONTINUOUS;
                ts.DataOrigin = IfcDataOriginEnum.MEASURED;
                ts.TimeStep = 604800; //7 days in secs
            });

            var ifcPrValueTimeSeries = model.Instances.New<IfcPropertyReferenceValue>(prv =>
            {
                prv.Name = "IfcPropertyReferenceValue:TimeSeries";
                prv.PropertyReference = ifcTimeSeries;
            });

            var ifcAddress = model.Instances.New<IfcPostalAddress>(a =>
            {
                a.InternalLocation = "Room 101";
                a.AddressLines.AddRange(new[] { new IfcLabel("12 New road"), new IfcLabel("DoxField") });
                a.Town = "Sunderland";
                a.PostalCode = "DL01 6SX";
            });
            var ifcPrValueAddress = model.Instances.New<IfcPropertyReferenceValue>(prv =>
            {
                prv.Name = "IfcPropertyReferenceValue:Address";
                prv.PropertyReference = ifcAddress;
            });
            var ifcTelecomAddress = model.Instances.New<IfcTelecomAddress>(a =>
            {
                a.TelephoneNumbers.Add(new IfcLabel("01325 6589965"));
                a.ElectronicMailAddresses.Add(new IfcLabel("bob@bobsworks.com"));
            });
            var ifcPrValueTelecom = model.Instances.New<IfcPropertyReferenceValue>(prv =>
            {
                prv.Name = "IfcPropertyReferenceValue:Telecom";
                prv.PropertyReference = ifcTelecomAddress;
            });

            // ifcelementQuantity 创建模型元素数量
            var ifcPropertySet = model.Instances.New<IfcPropertySet>(ps =>
            {
                ps.Name = "Test:IfcPropertySet";
                ps.Description = "Property Set";
                ps.HasProperties.Add(ifcPropertySingleValue);
                ps.HasProperties.Add(ifcPropertyEnumeratedValue);
                ps.HasProperties.Add(ifcPropertyBoundedValue);
                ps.HasProperties.Add(ifcPropertyTableValue);
                ps.HasProperties.Add(ifcPropertyListValue);
                ps.HasProperties.Add(ifcPrValueMaterial);
                ps.HasProperties.Add(ifcPrValueMatLayer);
                ps.HasProperties.Add(ifcPrValueRef);
                ps.HasProperties.Add(ifcPrValueTimeSeries);
                ps.HasProperties.Add(ifcPrValueAddress);
                ps.HasProperties.Add(ifcPrValueTelecom);
            });

            // 需要建立关系
            model.Instances.New<IfcRelDefinesByProperties>(rdbp =>
            {
                rdbp.Name = "Property Association";
                rdbp.Description = "IfcPropertySet associated to wall";
                rdbp.RelatedObjects.Add(wall);
                rdbp.RelatingPropertyDefinition = ifcPropertySet;
            });
        }

        private static void CreateElementQuantity(IfcStore model, IfcWallStandardCase wall)
        {
            // 创建模型元素数量
            // 首先我们需模型简单物理量，首先将使用模型量长度
            var ifcQuantityArea = model.Instances.New<IfcQuantityLength>(qa =>
            {
                qa.Name = "IfcQuantityArea:Area";
                qa.Description = "";
                qa.Unit = model.Instances.New<IfcSIUnit>(siu =>
                {
                    siu.UnitType = IfcUnitEnum.LENGTHUNIT;
                    siu.Prefix = IfcSIPrefix.MILLI;
                    siu.Name = IfcSIUnitName.METRE;
                });
                qa.LengthValue = 100.0;

            });

            // 然后，上下文相关单元的数量计数
            var ifcContextDependentUnit = model.Instances.New<IfcContextDependentUnit>(cd =>
            {
                cd.Dimensions = model.Instances.New<IfcDimensionalExponents>(de =>
                {
                    de.LengthExponent = 1;
                    de.MassExponent = 0;
                    de.TimeExponent = 0;
                    de.ElectricCurrentExponent = 0;
                    de.ThermodynamicTemperatureExponent = 0;
                    de.AmountOfSubstanceExponent = 0;
                    de.LuminousIntensityExponent = 0;
                });
                cd.UnitType = IfcUnitEnum.LENGTHUNIT;
                cd.Name = "Elephants";
            });
            var ifcQuantityCount = model.Instances.New<IfcQuantityCount>(qc =>
            {
                qc.Name = "IfcQuantityCount:Elephant";
                qc.CountValue = 12;
                qc.Unit = ifcContextDependentUnit;
            });


            // 使用转换单位
            var ifcConversionBasedUnit = model.Instances.New<IfcConversionBasedUnit>(cbu =>
            {
                cbu.ConversionFactor = model.Instances.New<IfcMeasureWithUnit>(mu =>
                {
                    mu.ValueComponent = new IfcRatioMeasure(25.4);
                    mu.UnitComponent = model.Instances.New<IfcSIUnit>(siu =>
                    {
                        siu.UnitType = IfcUnitEnum.LENGTHUNIT;
                        siu.Prefix = IfcSIPrefix.MILLI;
                        siu.Name = IfcSIUnitName.METRE;
                    });

                });
                cbu.Dimensions = model.Instances.New<IfcDimensionalExponents>(de =>
                {
                    de.LengthExponent = 1;
                    de.MassExponent = 0;
                    de.TimeExponent = 0;
                    de.ElectricCurrentExponent = 0;
                    de.ThermodynamicTemperatureExponent = 0;
                    de.AmountOfSubstanceExponent = 0;
                    de.LuminousIntensityExponent = 0;
                });
                cbu.UnitType = IfcUnitEnum.LENGTHUNIT;
                cbu.Name = "Inch";
            });
            var ifcQuantityLength = model.Instances.New<IfcQuantityLength>(qa =>
            {
                qa.Name = "IfcQuantityLength:Length";
                qa.Description = "";
                qa.Unit = ifcConversionBasedUnit;
                qa.LengthValue = 24.0;
            });

            // 创建 IfcElementQuantity
            var ifcElementQuantity = model.Instances.New<IfcElementQuantity>(eq =>
            {
                eq.Name = "Test:IfcElementQuantity";
                eq.Description = "Measurement quantity";
                eq.Quantities.Add(ifcQuantityArea);
                eq.Quantities.Add(ifcQuantityCount);
                eq.Quantities.Add(ifcQuantityLength);
            });

            // 创建关系
            model.Instances.New<IfcRelDefinesByProperties>(rdbp =>
            {
                rdbp.Name = "Area Association";
                rdbp.Description = "IfcElementQuantity associated to wall";
                rdbp.RelatedObjects.Add(wall);
                rdbp.RelatingPropertyDefinition = ifcElementQuantity;
            });
        }


        #endregion

        #region

        public ActionResult ToWexBim(string wFileName)
        {
            string fileName = Server.MapPath(@"\res\ifc\Ghasem.ifc");
            if (!string.IsNullOrEmpty(wFileName))
            {
                fileName = Server.MapPath(wFileName);
            }
            using (var model = IfcStore.Open(fileName))
            {
                var context = new Xbim3DModelContext(model);
                context.CreateContext();

                var wexBimFilename = Path.ChangeExtension(fileName, "wexBIM");
                using (var wexBiMfile = System.IO.File.Create(wexBimFilename))
                {
                    using (var wexBimBinaryWriter = new BinaryWriter(wexBiMfile))
                    {
                        model.SaveAsWexBim(wexBimBinaryWriter);
                        wexBimBinaryWriter.Close();
                    }
                    wexBiMfile.Close();
                }
                return Json(wexBimFilename, JsonRequestBehavior.AllowGet);
            }

        }
        // GET: /BimIfc/Index
        // 
        public ActionResult Index(string wFileName)
        {
            string fileName = Server.MapPath(@"\res\ifc\Ghasem.ifc");
            if (!string.IsNullOrEmpty(wFileName))
            {
                fileName = Server.MapPath(wFileName);
            }

            var lsInfo = new List<NodeInfo>();
            #region  
            using (var model = IfcStore.Open(fileName))
            {
                #region



                #endregion
            }
            #endregion
            return Content(JsonConvert.SerializeObject(lsInfo), "application/json");
            //return Json(lsInfo, JsonRequestBehavior.AllowGet);
        }

        // GET: /BimIfc/GetAllStoreys
        // 
        public ActionResult GetAllStoreys(string wFileName)
        {
            string fileName = Server.MapPath(@"\res\ifc\Ghasem.ifc");
            if (!string.IsNullOrEmpty(wFileName))
            {
                fileName = Server.MapPath(wFileName);
            }

            var lsInfo = new List<NodeInfo>();
            #region  
            using (var model = IfcStore.Open(fileName))
            {
                #region
                // 项目
                var prj = model.Instances.OfType<IIfcProject>().FirstOrDefault();
                if (prj != null)
                {
                    var nodeInfo = new NodeInfo { ID = prj.EntityLabel.ToString(), GlobalID = prj.GlobalId, TypeName = "项目", Name = prj.Name, Desc = prj.Description?.Value?.ToString() };
                    var properties = prj.IsDefinedBy
                      .Where(r => r.RelatingPropertyDefinition is IIfcPropertySet)
                      .SelectMany(r => ((IIfcPropertySet)r.RelatingPropertyDefinition).HasProperties)
                      .OfType<IIfcPropertySingleValue>();
                    foreach (var prop in properties)
                    {
                        nodeInfo.LsPropertie.Add(new NodePropertieInfo { Name = prop.Name, Value = prop.NominalValue.ToString() });
                    }
                    lsInfo.Add(nodeInfo);
                }

                // 场地
                var allSites = model.Instances.OfType<IIfcSite>().ToList();//  model.Instances.Where<IIfcSite>(d => d.IsTypedBy.Any()).ToList();
                allSites.ForEach(item =>
                {
                    var nodeInfo = new NodeInfo { PID = prj.EntityLabel.ToString(), ID = item.EntityLabel.ToString(), GlobalID = item.GlobalId, TypeName = "场地", Name = item.Name, Desc = item.SiteAddress?.Town?.ToString() };
                    var properties = item.IsDefinedBy
                      .Where(r => r.RelatingPropertyDefinition is IIfcPropertySet)
                      .SelectMany(r => ((IIfcPropertySet)r.RelatingPropertyDefinition).HasProperties)
                      .OfType<IIfcPropertySingleValue>();
                    foreach (var prop in properties)
                    {
                        nodeInfo.LsPropertie.Add(new NodePropertieInfo { Name = prop.Name, Value = prop.NominalValue.ToString() });
                    }
                    lsInfo.Add(nodeInfo);
                });
                // 建筑物
                var allBuilding = model.Instances.OfType<IIfcBuilding>().ToList();//  model.Instances.Where<IIfcBuilding>(d => d.IsTypedBy.Any()).ToList();
                allBuilding.ForEach(item =>
                {
                    var nodeInfo = new NodeInfo { PID = prj.EntityLabel.ToString(), ID = item.EntityLabel.ToString(), GlobalID = item.GlobalId, TypeName = "建筑物", Name = item.Name, Desc = item.Description?.Value?.ToString() };
                    var properties = item.IsDefinedBy
                      .Where(r => r.RelatingPropertyDefinition is IIfcPropertySet)
                      .SelectMany(r => ((IIfcPropertySet)r.RelatingPropertyDefinition).HasProperties)
                      .OfType<IIfcPropertySingleValue>();
                    foreach (var prop in properties)
                    {
                        nodeInfo.LsPropertie.Add(new NodePropertieInfo { Name = prop.Name, Value = prop.NominalValue.ToString() });
                    }
                    lsInfo.Add(nodeInfo);
                });
                // 建筑物楼层
                var allBuildingStorey = model.Instances.OfType<IIfcBuildingStorey>().ToList();//  model.Instances.Where<IfcBuildingStorey>(d => d.IsTypedBy.Any()).ToList();
                allBuildingStorey.ForEach(item =>
                {
                    var nodeInfo = new NodeInfo { PID = prj.EntityLabel.ToString(), ID = item.EntityLabel.ToString(), GlobalID = item.GlobalId, TypeName = "建筑物楼层", Name = item.Name, Desc = item.Description?.Value?.ToString() };
                    var properties = item.IsDefinedBy
                      .Where(r => r.RelatingPropertyDefinition is IIfcPropertySet)
                      .SelectMany(r => ((IIfcPropertySet)r.RelatingPropertyDefinition).HasProperties)
                      .OfType<IIfcPropertySingleValue>();
                    foreach (var prop in properties)
                    {
                        nodeInfo.LsPropertie.Add(new NodePropertieInfo { Name = prop.Name, Value = prop.NominalValue.ToString() });
                    }
                    lsInfo.Add(nodeInfo);
                });
                #endregion
            }
            #endregion
            return Content(JsonConvert.SerializeObject(lsInfo), "application/json");
            //return Json(lsInfo, JsonRequestBehavior.AllowGet);
        }
        // GET: /BimIfc/GetDomains
        // 
        public ActionResult GetDomains(string wFileName)
        {
            string fileName = Server.MapPath(@"\res\ifc\Ghasem.ifc");
            if (!string.IsNullOrEmpty(wFileName))
            {
                fileName = Server.MapPath(wFileName);
            }

            var lsInfo = new List<NodeInfo>();
            #region  
            using (var model = IfcStore.Open(fileName))
            {
                #region
                // 电气  IIfcElectricalElement
                var allSites = model.Instances.OfType<IIfcElectricAppliance>().ToList();//  model.Instances.Where<IIfcSite>(d => d.IsTypedBy.Any()).ToList();
                allSites.ForEach(item =>
                {
                    var nodeInfo = new NodeInfo { ID = item.EntityLabel.ToString(), GlobalID = item.GlobalId, TypeName = "电气", Name = item.Name, Desc = item.Description?.Value.ToString() };

                    var properties = item.IsDefinedBy
                    .Where(r => r.RelatingPropertyDefinition is IIfcPropertySet)
                    .SelectMany(r => ((IIfcPropertySet)r.RelatingPropertyDefinition).HasProperties)
                    .OfType<IIfcPropertySingleValue>();
                    foreach (var prop in properties)
                    {
                        nodeInfo.LsPropertie.Add(new NodePropertieInfo { Name = prop.Name, Value = prop.NominalValue.ToString() });
                    }
                    //var properties = item.IsDefinedBy
                    // .Where(r => r.RelatingPropertyDefinition is IIfcPropertySet)
                    // .SelectMany(r => ((IIfcPropertySet)r.RelatingPropertyDefinition).HasProperties)
                    // .OfType<IIfcPropertySingleValue>();
                    //foreach (var prop in properties)
                    //{
                    //    nodeInfo.LsPropertie.Add(new NodePropertieInfo { Name = prop.Name, Value = prop.NominalValue.ToString() });
                    //}
                    lsInfo.Add(nodeInfo);
                });

                #endregion
            }
            #endregion
            return Content(JsonConvert.SerializeObject(lsInfo), "application/json");
            //return Json(lsInfo, JsonRequestBehavior.AllowGet);
        }
        // GET: /BimIfc/GetEntityProperties
        // 
        public ActionResult GetEntityProperties(string wFileName, int id)
        {
            string fileName = Server.MapPath(@"\res\ifc\Ghasem.ifc");
            if (!string.IsNullOrEmpty(wFileName))
            {
                fileName = Server.MapPath(wFileName);
            }

            var LsPropertie = new List<NodePropertieInfo>();
            #region  
            using (var model = IfcStore.Open(fileName))
            {
                // var entity = model.Instances.OfType<IIfcBuildingElement>().Where(x => x.EntityLabel == id).FirstOrDefault();                 
                //if (entity!=null)
                //{
                //    var properties = entity.IsDefinedBy
                //      .Where(r => r.RelatingPropertyDefinition is IIfcPropertySet)
                //      .SelectMany(r => ((IIfcPropertySet)r.RelatingPropertyDefinition).HasProperties)
                //      .OfType<IIfcPropertySingleValue>();
                //    foreach (var prop in properties)
                //    {
                //        LsPropertie.Add(new NodePropertieInfo { Name = prop.Name, Value = prop.NominalValue.ToString() });
                //    }
                //}

                var entity = model.Instances.OfType<IIfcElement>().Where(x => x.EntityLabel == id).FirstOrDefault();
                if (entity != null)
                {
                    var properties = entity.IsDefinedBy
                      .Where(r => r.RelatingPropertyDefinition is IIfcPropertySet)
                      .SelectMany(r => ((IIfcPropertySet)r.RelatingPropertyDefinition).HasProperties)
                      .OfType<IIfcPropertySingleValue>();
                    foreach (var prop in properties)
                    {
                        LsPropertie.Add(new NodePropertieInfo { Name = prop.Name, Value = prop.NominalValue.ToString() });
                    }
                }

            }
            #endregion
            return Content(JsonConvert.SerializeObject(LsPropertie), "application/json");
            //return Json(lsInfo, JsonRequestBehavior.AllowGet);
        }

        #endregion



    }
}